﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Merger.Wav
{
    class WavFile
    {
        private string filePath;
        private WavHeader header;
        private WavFmtSChunk fmtChunk;
        private WavDataSChunk dataChunk;

        public WavFile(string filePath)
        {
            this.filePath = filePath;

            this.header = null;
            this.fmtChunk = null;
            this.dataChunk = null;
        }

        public WavFile(string filePath, bool getData)
        {
            this.filePath = filePath;

            createHeader(filePath);
            createFmtChunk(filePath);
            createDataChunk(filePath, getData);
        }

        private void createDataChunk(string filePath, bool getData)
        {
            using (BinaryReader reader = new BinaryReader(File.Open(filePath, FileMode.Open)))
            {
                reader.BaseStream.Seek(38, SeekOrigin.Begin);

                byte[] chunkId = reader.ReadBytes(4);
                byte[] chunkSize = reader.ReadBytes(4);
                utworzDataSubChunk(filePath, getData, reader, chunkId, chunkSize);
            }
        }

        private void utworzDataSubChunk(string filePath, bool getData, BinaryReader reader, byte[] chunkId, byte[] chunkSize)
        {
            if (getData)
            {
                int dataLength = WavDataSChunk.dataLength(chunkSize);
                byte[] data = reader.ReadBytes(dataLength);
                this.dataChunk = new WavDataSChunk(chunkId, chunkSize, data);
            }
            else this.dataChunk = new WavDataSChunk(chunkId, chunkSize, filePath);
        }

        private void createFmtChunk(string filePath)
        {
            using (BinaryReader reader = new BinaryReader(File.Open(filePath, FileMode.Open)))
            {
                reader.BaseStream.Seek(12, SeekOrigin.Begin);

                byte[] subchunkId = reader.ReadBytes(4);
                byte[] subchunkSize = reader.ReadBytes(4);
                byte[] audioFormat = reader.ReadBytes(2);
                byte[] numChannels = reader.ReadBytes(2);
                byte[] sampleRate = reader.ReadBytes(4);
                byte[] byteRate = reader.ReadBytes(4);
                byte[] blockAlign = reader.ReadBytes(2);
                byte[] bitsPerSample = reader.ReadBytes(2);

                this.fmtChunk = new WavFmtSChunk(subchunkId, subchunkSize, audioFormat, numChannels, sampleRate, byteRate, blockAlign, bitsPerSample);
            }
        }

        private void createHeader(string filePath)
        {
            using (BinaryReader reader = new BinaryReader(File.Open(filePath, FileMode.Open)))
            {
                byte[] chunkId = reader.ReadBytes(4);
                byte[] chunkSize = reader.ReadBytes(4);
                byte[] format = reader.ReadBytes(4);

                this.header = new WavHeader(chunkId, chunkSize, format);
            }
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            WavFile wavFile = obj as WavFile;
            if (wavFile == null)
                return false;

            return ((this.header == wavFile.header) && (this.fmtChunk == wavFile.fmtChunk) && 
                (this.dataChunk== wavFile.dataChunk));
        }

        public bool Equals(WavFile wavFile)
        {
            if (wavFile == null)
                return false;

            return ((this.header == wavFile.header) && (this.fmtChunk == wavFile.fmtChunk) &&
                (this.dataChunk == wavFile.dataChunk));
        }

        public override int GetHashCode()
        {
            return (this.header.GetHashCode() ^ this.fmtChunk.GetHashCode() ^ this.dataChunk.GetHashCode());
        }

        public static bool operator==(WavFile a, WavFile b)
        {
            if (Object.ReferenceEquals(a, b))
                return true;
            if ((a == null) || (b == null))
                return false;

            return ((a.header == b.header) && (a.fmtChunk == b.fmtChunk) && (a.dataChunk == b.dataChunk));
        }

        public static bool operator!=(WavFile a, WavFile b)
        {
            return !(a == b);
        }

        public bool canMerge(WavFile secondFile)
        {
            return this.fmtChunk.canMerge(secondFile.fmtChunk);
        }

        public void mergeFile(WavFile secondFile)
        {
            int mergeDataChunkSize = this.dataChunk.DataLength + secondFile.dataChunk.DataLength;
            int headerSize = 38 + mergeDataChunkSize;

            //this.dataChunk.DataLength = mergeDataChunkSize;
            //this.header.ChunkSize = headerSize;

            this.header.changeHeaderSize(this.filePath, headerSize);
            this.dataChunk.changeSubChunkSize(this.filePath, mergeDataChunkSize);
            secondFile.dataChunk.appendData(this.filePath);
        }
    }
}
